package com.uaroadshow.finale.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.JsonUtils;
import com.uaroadshow.entity.trade.Order;
import com.uaroadshow.entity.trade.PaymentRequest;
import com.uaroadshow.entity.trade.Product;
import com.uaroadshow.entity.trade.ProductStat;
import com.uaroadshow.entity.user.User;
import com.uaroadshow.entity.user.UserCourse;
import com.uaroadshow.entity.user.UserInfo;
import com.uaroadshow.finale.dao.OrderDao;
import com.uaroadshow.finale.dao.ProductDao;
import com.uaroadshow.finale.dao.UserDao;
import com.uaroadshow.finale.entity.Shopping;
import com.uaroadshow.finale.handler.PaymentHandler;
import com.uaroadshow.finale.service.OrderService;

/**
 *
 * @author Ark
 *
 */
@Service("orderService")
public class OrderServiceImpl extends DataServiceImpl<Order> implements OrderService {
    
    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Dao
    private ProductDao productDao;
    
    @Dao
    private UserDao userDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    @Dao
    private OrderDao orderDao;
    
    @Autowired
    private PaymentHandler paymentHandler;
    
    /* (non-Javadoc)
     * @see com.uaroadshow.finale.service.OrderService#create(com.uaroadshow.finale.entity.Shopping, com.uaroadshow.entity.user.User)
     */
    public Order create(Shopping shopping, User user) {
        
        // 1.1 check shopping valid
        if (!shopping.isValid()) {
            throw BusinessException.newInstance("500", "未填写必填项");
        }
        
        // 1.2 check product_stat
        Product product = genericDaoSupport.load(Product.class, shopping.getProductId());
        this.validateProductStat(product);
        
        // 2. update user_info
        UserInfo userInfo = userDao.getUserInfo(user);
        genericDaoSupport.update(userInfo.edit(shopping.getName(), shopping.getGender(), shopping.getAge(), shopping.getClothesSize(), shopping.getShoeSize()));
        
        // 3. create & return order
        Order order = new Order(product, user, userInfo);
        genericDaoSupport.save(order);
        
        return order;
        
    }

    /* (non-Javadoc)
     * @see com.uaroadshow.finale.service.OrderService#prepay(java.lang.Long, com.uaroadshow.entity.user.User, java.lang.String)
     */
    public Map<String, Object> pay(Long orderId, User user, String remoteIp) {
        
        Order order = genericDaoSupport.load(Order.class, orderId);
        
        // 1. validate product rest
        this.validateProductStat(order.getProduct());
        
        // 2. create payment request
        PaymentRequest paymentRequest = new PaymentRequest(order.getCode());
        genericDaoSupport.save(paymentRequest.initliaze());
        
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("order_no", paymentRequest.getOrderCode());
        parameters.put("request_no", paymentRequest.getCode());
        parameters.put("user_id", user.getOpenid());
        parameters.put("channel", "wechatpay");
        parameters.put("amount", order.getPrice());
        parameters.put("subject", "UA - " + order.getProduct().getName());  // FIXME
        
        // 3. call payment, do pay
        Map<String, Object> wechatPayContext = paymentHandler.generateWechatPayContext(parameters);
        logger.trace("#pay() - Get wechatPayContext here [{}]", JsonUtils.toJson(wechatPayContext));
        
        return wechatPayContext;
        
    }
    
    /* (non-Javadoc)
     * @see com.uaroadshow.finale.service.OrderService#paid(com.uaroadshow.entity.trade.PaymentRequest, java.lang.String, java.lang.String, java.lang.String)
     */
    public Order paid(PaymentRequest paymentRequest, String orderCode, String payCode, String payTime) {
        
        // 1. validate order
        Order order = orderDao.getOrder(orderCode);
        if (order == null) {
            throw new BusinessException("支付回调订单数据有误");
        }
        
        // 2. update payment request
        genericDaoSupport.update(paymentRequest.paid(payCode));
        
        // 3. update order
        genericDaoSupport.update(order.paid());
        
        // 4. create user_course
        UserCourse userCourse = new UserCourse(order);
        genericDaoSupport.save(userCourse);
        
        // 5. reduce product rest
        Product product = order.getProduct();
        if (product.isParent()) {
            
            // 1. reduce product_stat
            ProductStat productStat = productDao.getStat(product);
            genericDaoSupport.update(productStat.reduce());
            
            // 2. reduce child product_stat
            List<Product> childProducts = productDao.listChild(product);
            for (Product childProduct : childProducts) {
                ProductStat childProductStat = productDao.getStat(childProduct);
                genericDaoSupport.update(childProductStat.reduce());
            }
            
        } else {
            
            // 1. reduce product_stat
            ProductStat productStat = productDao.getStat(product);
            genericDaoSupport.update(productStat.reduce());
            
            // 2. reduce parent_product_stat
            this.reduceParentStat(product);
            
        }
        
        return order;
        
    }
    
    /**
     * 校验产品容量
     * 
     * @param product
     */
    private void validateProductStat(Product product) {

        ProductStat productStat = productDao.getStat(product);
        if (productStat.noRest()) {
            throw BusinessException.newInstance("600", "产品容量不足");
        }
        
        if (product.isParent()) {
            
            List<Product> childProducts = productDao.listChild(product);
            for (Product childProduct : childProducts) {
                ProductStat childProductStat = productDao.getStat(childProduct);
                if (childProductStat.noRest()) {
                    throw BusinessException.newInstance("600", "产品容量不足");
                }
                
            }
            
        }
        
    }
    
    /**
     * 减少父产品容量
     * 
     * @param product
     */
    private void reduceParentStat(Product product) {
        
        Product parentProduct = product.getParent();
        ProductStat parentProductStat = productDao.getStat(parentProduct);
        
        List<Product> childProducts = productDao.listChild(parentProduct);
        for (Product childProduct : childProducts) {
            
            ProductStat childProductStat = productDao.getStat(childProduct);
            int parentRests = parentProductStat.getRests();
            int childRests = childProductStat.getRests();
            
            if (childRests < parentRests) {       // 子产品容量低于父产品
                genericDaoSupport.update(parentProductStat.editRest(childRests));
            }
            
        }
        
    }
    
}
